<?php

namespace app\third\logic\phoneCode\driver;

use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use app\third\exceptions\ApiException;
use app\third\model\ThirdPhoneCode;

/**
 * 手机验证码
 * Class PhoneCode
 * @package app\third\logic
 */
class Ali extends Base
{
    protected $maxNums = 20;

    /**
     * 发送验证短信
     * @param string $type
     * @param string $phone
     * @param string $ip
     * @return bool
     * @throws \Exception
     */
    public function sendCode(string $type, string $phone, string $ip = '')
    {
        $total = ThirdPhoneCode::where('type', $type)
            ->where('phone', $phone)
            ->where('create_time', '>', date('Y-m-d 00:00:00', time() - 60 * 5))
            ->count();

        if ($total > $this->maxNums) {
            throw new \Exception('发送短信过于频繁，请稍后再试');
        }

        /** @var ThirdPhoneCode $exist */
        $exist = ThirdPhoneCode::where('type', $type)
            ->where('phone', $phone)
            ->where('status', ThirdPhoneCode::STATUS_NEW)
            ->find();
        if ($exist && $exist->isValid()) {
            ApiException::throws(ApiException::$smsRepeat);
        }
        $code = rand(1000, 9999);
        $model = ThirdPhoneCode::create([
            'type' => $type,
            'phone' => $phone,
            'code' => $code,
            'ip' => $ip
        ]);
        if (!$model->save()) {
            trace("数据库错误，{$phone}短信发送", 'error');
            return false;
        }
        $rs = false;
        try {
            $rs = $this->send($type, $phone, ['code' => $code]);
        } catch (ClientException $e) {
        }
        if (!$rs) {
            $model->status = ThirdPhoneCode::STATUS_FAIL;
            $model->save();
        }
        return $rs;
    }

    /**
     * 发送短信
     * @param $type
     * @param $phone
     * @param $params
     * @return bool
     * @throws ClientException
     */
    public function send($type, $phone, $params)
    {
        $config = $this->initClient();
        $tplKey = 'sms_tpl_' . $type;
        $template = isset($config[$tplKey]) ? $config[$tplKey] : null;
        if (!$template) {
            trace("短信模板{$tplKey}未配置，{$phone}短信发送", 'error');
            return false;
        }

        try {
            $options = [
                'PhoneNumbers' => $phone,
                'SignName' => $config['sms_ali_sign_name'],
                'TemplateCode' => $template,
                'TemplateParam' => json_encode($params),
            ];
            $result = AlibabaCloud::rpc()
                ->product('Dysmsapi')
                // ->scheme('https') // https | http
                ->version('2017-05-25')
                ->action('SendSms')
                ->method('POST')
                ->host('dysmsapi.aliyuncs.com')
                ->options([
                    'query' => $options,
                ])
                ->request()->toArray();
            if (!$result || ($result['Code'] != 'OK')) {
                $tmp = [
                    'options' => $options,
                    'result' => $result,
                ];
                $tmp = json_encode($tmp);
                trace("短信发送: {$tmp}", 'error');
                return false;
            }
            return true;
        } catch (ClientException $e) {
            trace($e->getErrorMessage(), 'error');
        } catch (ServerException $e) {
            trace($e->getErrorMessage(), 'error');
        }
        return false;
    }

    /**
     * 初始化
     * @return array
     * @throws ClientException
     * @throws \Exception
     */
    protected function initClient()
    {
        if ($this->init) {
            return $this->init;
        }
        $config = thinkConfigs('sms_ali.*');
        AlibabaCloud::accessKeyClient($config['sms_ali_appid'], $config['sms_ali_secret'])
            ->regionId('cn-hangzhou')
            ->asDefaultClient();;

        return $this->init = $config;
    }

}